home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / arch / mips / include / asm / atomic.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  18.3 KB  |  802 lines

  1. /*
  2.  * Atomic operations that C can't guarantee us.  Useful for
  3.  * resource counting etc..
  4.  *
  5.  * But use these as seldom as possible since they are much more slower
  6.  * than regular operations.
  7.  *
  8.  * This file is subject to the terms and conditions of the GNU General Public
  9.  * License.  See the file "COPYING" in the main directory of this archive
  10.  * for more details.
  11.  *
  12.  * Copyright (C) 1996, 97, 99, 2000, 03, 04, 06 by Ralf Baechle
  13.  */
  14. #ifndef _ASM_ATOMIC_H
  15. #define _ASM_ATOMIC_H
  16.  
  17. #include <linux/irqflags.h>
  18. #include <asm/barrier.h>
  19. #include <asm/cpu-features.h>
  20. #include <asm/war.h>
  21. #include <asm/system.h>
  22.  
  23. typedef struct { volatile int counter; } atomic_t;
  24.  
  25. #define ATOMIC_INIT(i)    { (i) }
  26.  
  27. /*
  28.  * atomic_read - read atomic variable
  29.  * @v: pointer of type atomic_t
  30.  *
  31.  * Atomically reads the value of @v.
  32.  */
  33. #define atomic_read(v)        ((v)->counter)
  34.  
  35. /*
  36.  * atomic_set - set atomic variable
  37.  * @v: pointer of type atomic_t
  38.  * @i: required value
  39.  *
  40.  * Atomically sets the value of @v to @i.
  41.  */
  42. #define atomic_set(v, i)        ((v)->counter = (i))
  43.  
  44. /*
  45.  * atomic_add - add integer to atomic variable
  46.  * @i: integer value to add
  47.  * @v: pointer of type atomic_t
  48.  *
  49.  * Atomically adds @i to @v.
  50.  */
  51. static __inline__ void atomic_add(int i, atomic_t * v)
  52. {
  53.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  54.         unsigned long temp;
  55.  
  56.         __asm__ __volatile__(
  57.         "    .set    mips3                    \n"
  58.         "1:    ll    %0, %1        # atomic_add        \n"
  59.         "    addu    %0, %2                    \n"
  60.         "    sc    %0, %1                    \n"
  61.         "    beqzl    %0, 1b                    \n"
  62.         "    .set    mips0                    \n"
  63.         : "=&r" (temp), "=m" (v->counter)
  64.         : "Ir" (i), "m" (v->counter));
  65.     } else if (cpu_has_llsc) {
  66.         unsigned long temp;
  67.  
  68.         __asm__ __volatile__(
  69.         "    .set    mips3                    \n"
  70.         "1:    ll    %0, %1        # atomic_add        \n"
  71.         "    addu    %0, %2                    \n"
  72.         "    sc    %0, %1                    \n"
  73.         "    beqz    %0, 2f                    \n"
  74.         "    .subsection 2                    \n"
  75.         "2:    b    1b                    \n"
  76.         "    .previous                    \n"
  77.         "    .set    mips0                    \n"
  78.         : "=&r" (temp), "=m" (v->counter)
  79.         : "Ir" (i), "m" (v->counter));
  80.     } else {
  81.         unsigned long flags;
  82.  
  83.         raw_local_irq_save(flags);
  84.         v->counter += i;
  85.         raw_local_irq_restore(flags);
  86.     }
  87. }
  88.  
  89. /*
  90.  * atomic_sub - subtract the atomic variable
  91.  * @i: integer value to subtract
  92.  * @v: pointer of type atomic_t
  93.  *
  94.  * Atomically subtracts @i from @v.
  95.  */
  96. static __inline__ void atomic_sub(int i, atomic_t * v)
  97. {
  98.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  99.         unsigned long temp;
  100.  
  101.         __asm__ __volatile__(
  102.         "    .set    mips3                    \n"
  103.         "1:    ll    %0, %1        # atomic_sub        \n"
  104.         "    subu    %0, %2                    \n"
  105.         "    sc    %0, %1                    \n"
  106.         "    beqzl    %0, 1b                    \n"
  107.         "    .set    mips0                    \n"
  108.         : "=&r" (temp), "=m" (v->counter)
  109.         : "Ir" (i), "m" (v->counter));
  110.     } else if (cpu_has_llsc) {
  111.         unsigned long temp;
  112.  
  113.         __asm__ __volatile__(
  114.         "    .set    mips3                    \n"
  115.         "1:    ll    %0, %1        # atomic_sub        \n"
  116.         "    subu    %0, %2                    \n"
  117.         "    sc    %0, %1                    \n"
  118.         "    beqz    %0, 2f                    \n"
  119.         "    .subsection 2                    \n"
  120.         "2:    b    1b                    \n"
  121.         "    .previous                    \n"
  122.         "    .set    mips0                    \n"
  123.         : "=&r" (temp), "=m" (v->counter)
  124.         : "Ir" (i), "m" (v->counter));
  125.     } else {
  126.         unsigned long flags;
  127.  
  128.         raw_local_irq_save(flags);
  129.         v->counter -= i;
  130.         raw_local_irq_restore(flags);
  131.     }
  132. }
  133.  
  134. /*
  135.  * Same as above, but return the result value
  136.  */
  137. static __inline__ int atomic_add_return(int i, atomic_t * v)
  138. {
  139.     unsigned long result;
  140.  
  141.     smp_llsc_mb();
  142.  
  143.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  144.         unsigned long temp;
  145.  
  146.         __asm__ __volatile__(
  147.         "    .set    mips3                    \n"
  148.         "1:    ll    %1, %2        # atomic_add_return    \n"
  149.         "    addu    %0, %1, %3                \n"
  150.         "    sc    %0, %2                    \n"
  151.         "    beqzl    %0, 1b                    \n"
  152.         "    addu    %0, %1, %3                \n"
  153.         "    .set    mips0                    \n"
  154.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  155.         : "Ir" (i), "m" (v->counter)
  156.         : "memory");
  157.     } else if (cpu_has_llsc) {
  158.         unsigned long temp;
  159.  
  160.         __asm__ __volatile__(
  161.         "    .set    mips3                    \n"
  162.         "1:    ll    %1, %2        # atomic_add_return    \n"
  163.         "    addu    %0, %1, %3                \n"
  164.         "    sc    %0, %2                    \n"
  165.         "    beqz    %0, 2f                    \n"
  166.         "    addu    %0, %1, %3                \n"
  167.         "    .subsection 2                    \n"
  168.         "2:    b    1b                    \n"
  169.         "    .previous                    \n"
  170.         "    .set    mips0                    \n"
  171.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  172.         : "Ir" (i), "m" (v->counter)
  173.         : "memory");
  174.     } else {
  175.         unsigned long flags;
  176.  
  177.         raw_local_irq_save(flags);
  178.         result = v->counter;
  179.         result += i;
  180.         v->counter = result;
  181.         raw_local_irq_restore(flags);
  182.     }
  183.  
  184.     smp_llsc_mb();
  185.  
  186.     return result;
  187. }
  188.  
  189. static __inline__ int atomic_sub_return(int i, atomic_t * v)
  190. {
  191.     unsigned long result;
  192.  
  193.     smp_llsc_mb();
  194.  
  195.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  196.         unsigned long temp;
  197.  
  198.         __asm__ __volatile__(
  199.         "    .set    mips3                    \n"
  200.         "1:    ll    %1, %2        # atomic_sub_return    \n"
  201.         "    subu    %0, %1, %3                \n"
  202.         "    sc    %0, %2                    \n"
  203.         "    beqzl    %0, 1b                    \n"
  204.         "    subu    %0, %1, %3                \n"
  205.         "    .set    mips0                    \n"
  206.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  207.         : "Ir" (i), "m" (v->counter)
  208.         : "memory");
  209.     } else if (cpu_has_llsc) {
  210.         unsigned long temp;
  211.  
  212.         __asm__ __volatile__(
  213.         "    .set    mips3                    \n"
  214.         "1:    ll    %1, %2        # atomic_sub_return    \n"
  215.         "    subu    %0, %1, %3                \n"
  216.         "    sc    %0, %2                    \n"
  217.         "    beqz    %0, 2f                    \n"
  218.         "    subu    %0, %1, %3                \n"
  219.         "    .subsection 2                    \n"
  220.         "2:    b    1b                    \n"
  221.         "    .previous                    \n"
  222.         "    .set    mips0                    \n"
  223.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  224.         : "Ir" (i), "m" (v->counter)
  225.         : "memory");
  226.     } else {
  227.         unsigned long flags;
  228.  
  229.         raw_local_irq_save(flags);
  230.         result = v->counter;
  231.         result -= i;
  232.         v->counter = result;
  233.         raw_local_irq_restore(flags);
  234.     }
  235.  
  236.     smp_llsc_mb();
  237.  
  238.     return result;
  239. }
  240.  
  241. /*
  242.  * atomic_sub_if_positive - conditionally subtract integer from atomic variable
  243.  * @i: integer value to subtract
  244.  * @v: pointer of type atomic_t
  245.  *
  246.  * Atomically test @v and subtract @i if @v is greater or equal than @i.
  247.  * The function returns the old value of @v minus @i.
  248.  */
  249. static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
  250. {
  251.     unsigned long result;
  252.  
  253.     smp_llsc_mb();
  254.  
  255.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  256.         unsigned long temp;
  257.  
  258.         __asm__ __volatile__(
  259.         "    .set    mips3                    \n"
  260.         "1:    ll    %1, %2        # atomic_sub_if_positive\n"
  261.         "    subu    %0, %1, %3                \n"
  262.         "    bltz    %0, 1f                    \n"
  263.         "    sc    %0, %2                    \n"
  264.         "    .set    noreorder                \n"
  265.         "    beqzl    %0, 1b                    \n"
  266.         "     subu    %0, %1, %3                \n"
  267.         "    .set    reorder                    \n"
  268.         "1:                            \n"
  269.         "    .set    mips0                    \n"
  270.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  271.         : "Ir" (i), "m" (v->counter)
  272.         : "memory");
  273.     } else if (cpu_has_llsc) {
  274.         unsigned long temp;
  275.  
  276.         __asm__ __volatile__(
  277.         "    .set    mips3                    \n"
  278.         "1:    ll    %1, %2        # atomic_sub_if_positive\n"
  279.         "    subu    %0, %1, %3                \n"
  280.         "    bltz    %0, 1f                    \n"
  281.         "    sc    %0, %2                    \n"
  282.         "    .set    noreorder                \n"
  283.         "    beqz    %0, 2f                    \n"
  284.         "     subu    %0, %1, %3                \n"
  285.         "    .set    reorder                    \n"
  286.         "    .subsection 2                    \n"
  287.         "2:    b    1b                    \n"
  288.         "    .previous                    \n"
  289.         "1:                            \n"
  290.         "    .set    mips0                    \n"
  291.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  292.         : "Ir" (i), "m" (v->counter)
  293.         : "memory");
  294.     } else {
  295.         unsigned long flags;
  296.  
  297.         raw_local_irq_save(flags);
  298.         result = v->counter;
  299.         result -= i;
  300.         if (result >= 0)
  301.             v->counter = result;
  302.         raw_local_irq_restore(flags);
  303.     }
  304.  
  305.     smp_llsc_mb();
  306.  
  307.     return result;
  308. }
  309.  
  310. #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
  311. #define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
  312.  
  313. /**
  314.  * atomic_add_unless - add unless the number is a given value
  315.  * @v: pointer of type atomic_t
  316.  * @a: the amount to add to v...
  317.  * @u: ...unless v is equal to u.
  318.  *
  319.  * Atomically adds @a to @v, so long as it was not @u.
  320.  * Returns non-zero if @v was not @u, and zero otherwise.
  321.  */
  322. static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
  323. {
  324.     int c, old;
  325.     c = atomic_read(v);
  326.     for (;;) {
  327.         if (unlikely(c == (u)))
  328.             break;
  329.         old = atomic_cmpxchg((v), c, c + (a));
  330.         if (likely(old == c))
  331.             break;
  332.         c = old;
  333.     }
  334.     return c != (u);
  335. }
  336. #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
  337.  
  338. #define atomic_dec_return(v) atomic_sub_return(1, (v))
  339. #define atomic_inc_return(v) atomic_add_return(1, (v))
  340.  
  341. /*
  342.  * atomic_sub_and_test - subtract value from variable and test result
  343.  * @i: integer value to subtract
  344.  * @v: pointer of type atomic_t
  345.  *
  346.  * Atomically subtracts @i from @v and returns
  347.  * true if the result is zero, or false for all
  348.  * other cases.
  349.  */
  350. #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
  351.  
  352. /*
  353.  * atomic_inc_and_test - increment and test
  354.  * @v: pointer of type atomic_t
  355.  *
  356.  * Atomically increments @v by 1
  357.  * and returns true if the result is zero, or false for all
  358.  * other cases.
  359.  */
  360. #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
  361.  
  362. /*
  363.  * atomic_dec_and_test - decrement by 1 and test
  364.  * @v: pointer of type atomic_t
  365.  *
  366.  * Atomically decrements @v by 1 and
  367.  * returns true if the result is 0, or false for all other
  368.  * cases.
  369.  */
  370. #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
  371.  
  372. /*
  373.  * atomic_dec_if_positive - decrement by 1 if old value positive
  374.  * @v: pointer of type atomic_t
  375.  */
  376. #define atomic_dec_if_positive(v)    atomic_sub_if_positive(1, v)
  377.  
  378. /*
  379.  * atomic_inc - increment atomic variable
  380.  * @v: pointer of type atomic_t
  381.  *
  382.  * Atomically increments @v by 1.
  383.  */
  384. #define atomic_inc(v) atomic_add(1, (v))
  385.  
  386. /*
  387.  * atomic_dec - decrement and test
  388.  * @v: pointer of type atomic_t
  389.  *
  390.  * Atomically decrements @v by 1.
  391.  */
  392. #define atomic_dec(v) atomic_sub(1, (v))
  393.  
  394. /*
  395.  * atomic_add_negative - add and test if negative
  396.  * @v: pointer of type atomic_t
  397.  * @i: integer value to add
  398.  *
  399.  * Atomically adds @i to @v and returns true
  400.  * if the result is negative, or false when
  401.  * result is greater than or equal to zero.
  402.  */
  403. #define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0)
  404.  
  405. #ifdef CONFIG_64BIT
  406.  
  407. typedef struct { volatile long counter; } atomic64_t;
  408.  
  409. #define ATOMIC64_INIT(i)    { (i) }
  410.  
  411. /*
  412.  * atomic64_read - read atomic variable
  413.  * @v: pointer of type atomic64_t
  414.  *
  415.  */
  416. #define atomic64_read(v)    ((v)->counter)
  417.  
  418. /*
  419.  * atomic64_set - set atomic variable
  420.  * @v: pointer of type atomic64_t
  421.  * @i: required value
  422.  */
  423. #define atomic64_set(v, i)    ((v)->counter = (i))
  424.  
  425. /*
  426.  * atomic64_add - add integer to atomic variable
  427.  * @i: integer value to add
  428.  * @v: pointer of type atomic64_t
  429.  *
  430.  * Atomically adds @i to @v.
  431.  */
  432. static __inline__ void atomic64_add(long i, atomic64_t * v)
  433. {
  434.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  435.         unsigned long temp;
  436.  
  437.         __asm__ __volatile__(
  438.         "    .set    mips3                    \n"
  439.         "1:    lld    %0, %1        # atomic64_add        \n"
  440.         "    addu    %0, %2                    \n"
  441.         "    scd    %0, %1                    \n"
  442.         "    beqzl    %0, 1b                    \n"
  443.         "    .set    mips0                    \n"
  444.         : "=&r" (temp), "=m" (v->counter)
  445.         : "Ir" (i), "m" (v->counter));
  446.     } else if (cpu_has_llsc) {
  447.         unsigned long temp;
  448.  
  449.         __asm__ __volatile__(
  450.         "    .set    mips3                    \n"
  451.         "1:    lld    %0, %1        # atomic64_add        \n"
  452.         "    addu    %0, %2                    \n"
  453.         "    scd    %0, %1                    \n"
  454.         "    beqz    %0, 2f                    \n"
  455.         "    .subsection 2                    \n"
  456.         "2:    b    1b                    \n"
  457.         "    .previous                    \n"
  458.         "    .set    mips0                    \n"
  459.         : "=&r" (temp), "=m" (v->counter)
  460.         : "Ir" (i), "m" (v->counter));
  461.     } else {
  462.         unsigned long flags;
  463.  
  464.         raw_local_irq_save(flags);
  465.         v->counter += i;
  466.         raw_local_irq_restore(flags);
  467.     }
  468. }
  469.  
  470. /*
  471.  * atomic64_sub - subtract the atomic variable
  472.  * @i: integer value to subtract
  473.  * @v: pointer of type atomic64_t
  474.  *
  475.  * Atomically subtracts @i from @v.
  476.  */
  477. static __inline__ void atomic64_sub(long i, atomic64_t * v)
  478. {
  479.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  480.         unsigned long temp;
  481.  
  482.         __asm__ __volatile__(
  483.         "    .set    mips3                    \n"
  484.         "1:    lld    %0, %1        # atomic64_sub        \n"
  485.         "    subu    %0, %2                    \n"
  486.         "    scd    %0, %1                    \n"
  487.         "    beqzl    %0, 1b                    \n"
  488.         "    .set    mips0                    \n"
  489.         : "=&r" (temp), "=m" (v->counter)
  490.         : "Ir" (i), "m" (v->counter));
  491.     } else if (cpu_has_llsc) {
  492.         unsigned long temp;
  493.  
  494.         __asm__ __volatile__(
  495.         "    .set    mips3                    \n"
  496.         "1:    lld    %0, %1        # atomic64_sub        \n"
  497.         "    subu    %0, %2                    \n"
  498.         "    scd    %0, %1                    \n"
  499.         "    beqz    %0, 2f                    \n"
  500.         "    .subsection 2                    \n"
  501.         "2:    b    1b                    \n"
  502.         "    .previous                    \n"
  503.         "    .set    mips0                    \n"
  504.         : "=&r" (temp), "=m" (v->counter)
  505.         : "Ir" (i), "m" (v->counter));
  506.     } else {
  507.         unsigned long flags;
  508.  
  509.         raw_local_irq_save(flags);
  510.         v->counter -= i;
  511.         raw_local_irq_restore(flags);
  512.     }
  513. }
  514.  
  515. /*
  516.  * Same as above, but return the result value
  517.  */
  518. static __inline__ long atomic64_add_return(long i, atomic64_t * v)
  519. {
  520.     unsigned long result;
  521.  
  522.     smp_llsc_mb();
  523.  
  524.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  525.         unsigned long temp;
  526.  
  527.         __asm__ __volatile__(
  528.         "    .set    mips3                    \n"
  529.         "1:    lld    %1, %2        # atomic64_add_return    \n"
  530.         "    addu    %0, %1, %3                \n"
  531.         "    scd    %0, %2                    \n"
  532.         "    beqzl    %0, 1b                    \n"
  533.         "    addu    %0, %1, %3                \n"
  534.         "    .set    mips0                    \n"
  535.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  536.         : "Ir" (i), "m" (v->counter)
  537.         : "memory");
  538.     } else if (cpu_has_llsc) {
  539.         unsigned long temp;
  540.  
  541.         __asm__ __volatile__(
  542.         "    .set    mips3                    \n"
  543.         "1:    lld    %1, %2        # atomic64_add_return    \n"
  544.         "    addu    %0, %1, %3                \n"
  545.         "    scd    %0, %2                    \n"
  546.         "    beqz    %0, 2f                    \n"
  547.         "    addu    %0, %1, %3                \n"
  548.         "    .subsection 2                    \n"
  549.         "2:    b    1b                    \n"
  550.         "    .previous                    \n"
  551.         "    .set    mips0                    \n"
  552.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  553.         : "Ir" (i), "m" (v->counter)
  554.         : "memory");
  555.     } else {
  556.         unsigned long flags;
  557.  
  558.         raw_local_irq_save(flags);
  559.         result = v->counter;
  560.         result += i;
  561.         v->counter = result;
  562.         raw_local_irq_restore(flags);
  563.     }
  564.  
  565.     smp_llsc_mb();
  566.  
  567.     return result;
  568. }
  569.  
  570. static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
  571. {
  572.     unsigned long result;
  573.  
  574.     smp_llsc_mb();
  575.  
  576.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  577.         unsigned long temp;
  578.  
  579.         __asm__ __volatile__(
  580.         "    .set    mips3                    \n"
  581.         "1:    lld    %1, %2        # atomic64_sub_return    \n"
  582.         "    subu    %0, %1, %3                \n"
  583.         "    scd    %0, %2                    \n"
  584.         "    beqzl    %0, 1b                    \n"
  585.         "    subu    %0, %1, %3                \n"
  586.         "    .set    mips0                    \n"
  587.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  588.         : "Ir" (i), "m" (v->counter)
  589.         : "memory");
  590.     } else if (cpu_has_llsc) {
  591.         unsigned long temp;
  592.  
  593.         __asm__ __volatile__(
  594.         "    .set    mips3                    \n"
  595.         "1:    lld    %1, %2        # atomic64_sub_return    \n"
  596.         "    subu    %0, %1, %3                \n"
  597.         "    scd    %0, %2                    \n"
  598.         "    beqz    %0, 2f                    \n"
  599.         "    subu    %0, %1, %3                \n"
  600.         "    .subsection 2                    \n"
  601.         "2:    b    1b                    \n"
  602.         "    .previous                    \n"
  603.         "    .set    mips0                    \n"
  604.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  605.         : "Ir" (i), "m" (v->counter)
  606.         : "memory");
  607.     } else {
  608.         unsigned long flags;
  609.  
  610.         raw_local_irq_save(flags);
  611.         result = v->counter;
  612.         result -= i;
  613.         v->counter = result;
  614.         raw_local_irq_restore(flags);
  615.     }
  616.  
  617.     smp_llsc_mb();
  618.  
  619.     return result;
  620. }
  621.  
  622. /*
  623.  * atomic64_sub_if_positive - conditionally subtract integer from atomic variable
  624.  * @i: integer value to subtract
  625.  * @v: pointer of type atomic64_t
  626.  *
  627.  * Atomically test @v and subtract @i if @v is greater or equal than @i.
  628.  * The function returns the old value of @v minus @i.
  629.  */
  630. static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
  631. {
  632.     unsigned long result;
  633.  
  634.     smp_llsc_mb();
  635.  
  636.     if (cpu_has_llsc && R10000_LLSC_WAR) {
  637.         unsigned long temp;
  638.  
  639.         __asm__ __volatile__(
  640.         "    .set    mips3                    \n"
  641.         "1:    lld    %1, %2        # atomic64_sub_if_positive\n"
  642.         "    dsubu    %0, %1, %3                \n"
  643.         "    bltz    %0, 1f                    \n"
  644.         "    scd    %0, %2                    \n"
  645.         "    .set    noreorder                \n"
  646.         "    beqzl    %0, 1b                    \n"
  647.         "     dsubu    %0, %1, %3                \n"
  648.         "    .set    reorder                    \n"
  649.         "1:                            \n"
  650.         "    .set    mips0                    \n"
  651.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  652.         : "Ir" (i), "m" (v->counter)
  653.         : "memory");
  654.     } else if (cpu_has_llsc) {
  655.         unsigned long temp;
  656.  
  657.         __asm__ __volatile__(
  658.         "    .set    mips3                    \n"
  659.         "1:    lld    %1, %2        # atomic64_sub_if_positive\n"
  660.         "    dsubu    %0, %1, %3                \n"
  661.         "    bltz    %0, 1f                    \n"
  662.         "    scd    %0, %2                    \n"
  663.         "    .set    noreorder                \n"
  664.         "    beqz    %0, 2f                    \n"
  665.         "     dsubu    %0, %1, %3                \n"
  666.         "    .set    reorder                    \n"
  667.         "    .subsection 2                    \n"
  668.         "2:    b    1b                    \n"
  669.         "    .previous                    \n"
  670.         "1:                            \n"
  671.         "    .set    mips0                    \n"
  672.         : "=&r" (result), "=&r" (temp), "=m" (v->counter)
  673.         : "Ir" (i), "m" (v->counter)
  674.         : "memory");
  675.     } else {
  676.         unsigned long flags;
  677.  
  678.         raw_local_irq_save(flags);
  679.         result = v->counter;
  680.         result -= i;
  681.         if (result >= 0)
  682.             v->counter = result;
  683.         raw_local_irq_restore(flags);
  684.     }
  685.  
  686.     smp_llsc_mb();
  687.  
  688.     return result;
  689. }
  690.  
  691. #define atomic64_cmpxchg(v, o, n) \
  692.     ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
  693. #define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
  694.  
  695. /**
  696.  * atomic64_add_unless - add unless the number is a given value
  697.  * @v: pointer of type atomic64_t
  698.  * @a: the amount to add to v...
  699.  * @u: ...unless v is equal to u.
  700.  *
  701.  * Atomically adds @a to @v, so long as it was not @u.
  702.  * Returns non-zero if @v was not @u, and zero otherwise.
  703.  */
  704. static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
  705. {
  706.     long c, old;
  707.     c = atomic64_read(v);
  708.     for (;;) {
  709.         if (unlikely(c == (u)))
  710.             break;
  711.         old = atomic64_cmpxchg((v), c, c + (a));
  712.         if (likely(old == c))
  713.             break;
  714.         c = old;
  715.     }
  716.     return c != (u);
  717. }
  718.  
  719. #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
  720.  
  721. #define atomic64_dec_return(v) atomic64_sub_return(1, (v))
  722. #define atomic64_inc_return(v) atomic64_add_return(1, (v))
  723.  
  724. /*
  725.  * atomic64_sub_and_test - subtract value from variable and test result
  726.  * @i: integer value to subtract
  727.  * @v: pointer of type atomic64_t
  728.  *
  729.  * Atomically subtracts @i from @v and returns
  730.  * true if the result is zero, or false for all
  731.  * other cases.
  732.  */
  733. #define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0)
  734.  
  735. /*
  736.  * atomic64_inc_and_test - increment and test
  737.  * @v: pointer of type atomic64_t
  738.  *
  739.  * Atomically increments @v by 1
  740.  * and returns true if the result is zero, or false for all
  741.  * other cases.
  742.  */
  743. #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
  744.  
  745. /*
  746.  * atomic64_dec_and_test - decrement by 1 and test
  747.  * @v: pointer of type atomic64_t
  748.  *
  749.  * Atomically decrements @v by 1 and
  750.  * returns true if the result is 0, or false for all other
  751.  * cases.
  752.  */
  753. #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0)
  754.  
  755. /*
  756.  * atomic64_dec_if_positive - decrement by 1 if old value positive
  757.  * @v: pointer of type atomic64_t
  758.  */
  759. #define atomic64_dec_if_positive(v)    atomic64_sub_if_positive(1, v)
  760.  
  761. /*
  762.  * atomic64_inc - increment atomic variable
  763.  * @v: pointer of type atomic64_t
  764.  *
  765.  * Atomically increments @v by 1.
  766.  */
  767. #define atomic64_inc(v) atomic64_add(1, (v))
  768.  
  769. /*
  770.  * atomic64_dec - decrement and test
  771.  * @v: pointer of type atomic64_t
  772.  *
  773.  * Atomically decrements @v by 1.
  774.  */
  775. #define atomic64_dec(v) atomic64_sub(1, (v))
  776.  
  777. /*
  778.  * atomic64_add_negative - add and test if negative
  779.  * @v: pointer of type atomic64_t
  780.  * @i: integer value to add
  781.  *
  782.  * Atomically adds @i to @v and returns true
  783.  * if the result is negative, or false when
  784.  * result is greater than or equal to zero.
  785.  */
  786. #define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0)
  787.  
  788. #endif /* CONFIG_64BIT */
  789.  
  790. /*
  791.  * atomic*_return operations are serializing but not the non-*_return
  792.  * versions.
  793.  */
  794. #define smp_mb__before_atomic_dec()    smp_llsc_mb()
  795. #define smp_mb__after_atomic_dec()    smp_llsc_mb()
  796. #define smp_mb__before_atomic_inc()    smp_llsc_mb()
  797. #define smp_mb__after_atomic_inc()    smp_llsc_mb()
  798.  
  799. #include <asm-generic/atomic.h>
  800.  
  801. #endif /* _ASM_ATOMIC_H */
  802.